-- PinocchioM
-- Created by panyl
-- 匹诺曹

module("PinocchioM", package.seeall);

local LIMIT_NOSE_SIZE  = 10;

local whenLeaveDungeon;

-- 所有的规则处理子模块
local rules = {};

-- 石柱配置
local fairys   = {};
local quetions = {};
local fairy_list   = {};
local quetion_list = {};

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    fairy_list   = {};
    quetion_list = {};

    -- 载入所有的规则处理子模块
    rules = LOAD_PATH("game/logic/module/pinocchio");

    -- 转换下machines信息表
    local fairy_CSV = get_fairy_CSV();
    for i = 1, #fairy_CSV do
        fairys[fairy_CSV[i].class_id] = fairy_CSV[i];
    end

    fairy_list = table.keys(fairys);
    table.sort(fairy_list);

    local fairy_quetion_CSV = get_fairy_quetion_CSV();
    for i = 1, #fairy_quetion_CSV do
        local row = fairy_quetion_CSV[i];
        quetions[row.id] = row;

        local arr = string.explode(row["speaker"] or "", "|");

        if sizeof(arr) > 0 then
            for _, id in pairs(arr) do
                local fairy_id = tonumber(id);
                quetion_list[fairy_id] = quetion_list[fairy_id] or {};

                table.insert(quetion_list[fairy_id], row.id);
            end
        end
    end

    -- 排序一遍，确保两端一致
    for _, id in pairs(fairy_list) do
        if quetion_list[id] then
            table.sort(quetion_list[id]);
        end
    end

    fairy_quetion_CSV = {};
    fairy_CSV = {};
end

function init()
    loadCsv();

    -- 关注玩家离开地牢的事件
    EventMgr.removeAll("PinocchioM");

    EventMgr.register("PinocchioM", event.LEAVE_DUNGEON, whenLeaveDungeon);

    EventMgr.register("PinocchioM", event.ANSWER_FAIRY_QUETION, do_bonus_notify);
end

whenLeaveDungeon = function(para)
    -- 删除本次迷宫统计
    ME.user.dbase:delete("normal_fairy_stat");
end

-- 抽取问题
function fetch_fairy_quetion(fairy_id)
    local list = quetion_list[fairy_id];
    if sizeof(list) <= 0 then
        trace("PinocchioM", "没有仙女%d数据", fairy_id);
        return 0;
    end

    local arr = {};
    for _, id in ipairs(list) do
        repeat
            -- 次数限制
            local limit = query_quetion(id, "limit") or {};
            if limit["per"] and get_quetion_count(id) >= limit["per"] then
                trace("PinocchioM", "问题%d已经超出每次限制", id);
                break;
            end
            if limit["weekly"] and get_quetion_count(id, "weekly") >= limit["weekly"] then
                trace("PinocchioM", "问题%d已经超出每周限制", id);
                break;
            end
            if limit["forever"] and get_quetion_count(id, "forever") >= limit["forever"] then
                trace("PinocchioM", "问题%d已经超出永久限制", id);
                break;
            end

            local rule = query_quetion(id, "rule");
            local mod = rules[rule];

            -- 子规则过滤一下
            if mod and mod.fetch and false ~= mod.fetch(id) then
                table.insert(arr, { ["id"] = id, ["ratio"] = query_quetion(id, "weight"), });
            end

        until true;
    end

    if sizeof(arr) <= 0 then
        return 0;
    end

    -- 根据权重选取一个
    local ret = fetchElemBySeed(arr, DungeonM.getRandSeed("fetch_fairy"));

    return ret["id"];
end

-- 正确答案奖励
function calc_quetion_bonus(quetion_id)
    local rule = query_quetion(quetion_id, "rule");
    local mod = rules[rule];

    if not mod or not mod.calc_bonus then
        return {};
    end

    return mod.calc_bonus(quetion_id) or {};
end

function query(id, path)
    local m = fairys[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

function query_quetion(id, path)
    local m = quetions[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 统计问题
function quetion_stat(id)
    -- 1. 每次迷宫的统计
    local stat = ME.user.dbase:query("normal_fairy_stat", {});
    stat[id] = tonumber(stat[id]) + 1;
    ME.user.dbase:set("normal_fairy_stat", stat);

    -- 2. 每周统计
    stat = ME.user.dbase:query("weekly_fairy_stat", {});
    stat[id] = tonumber(stat[id]) + 1;
    ME.user.dbase:set("weekly_fairy_stat", stat);

    -- 永久统计
    local limit = query_quetion(id, "limit") or {};
    if limit["forever"] then
        stat = ME.user.dbase:query("forever_fairy_stat", {});
        stat[id] = tonumber(stat[id]) + 1;
        ME.user.dbase:set("forever_fairy_stat", stat);
    end
end

-- 获取次数
function get_quetion_count(id, typ)
    local stat = {};

    if not typ then
        -- 普通的
        stat = ME.user.dbase:query("normal_fairy_stat", {});
    elseif "weekly" == typ then
        stat = ME.user.dbase:query("weekly_fairy_stat", {});
    elseif "forever" then
        stat = ME.user.dbase:query("forever_fairy_stat", {});
    end

    return tonumber(stat[id]);
end

-- 抽取仙女id
function fetch_fairy()
    local nose_size = ME.user:queryAttrib("nose_size");
    local list = {};

    for _, id in ipairs(fairy_list) do
        repeat
            local info = fairys[id];

            -- 没有达到要求
            if type(info["nose_size"]) == "number" and info["nose_size"] > nose_size then
                break;
            end

            -- 如果有限制次数
            if type(info["limit_times"]) == "number" and
                CombatStatM.getFieldStat(info["alias"]) >= info["limit_times"] then
                break;
            end

            local dbase = info["dbase"] or {};
            if dbase["need_equip"] and not EquipM.isEquiped(dbase["need_equip"]) then
                break;
            end

            table.insert(list, { ["id"] = id, ["ratio"] = info["weight"], });
        until true;
    end

    if sizeof(list) <= 0 then
        return {};
    end

    -- 按权重抽取一个
    local ret = fetchElemBySeed(list, DungeonM.getRandSeed("fetch_fairy"));

    local fairy_id = ret["id"];
    local quetion_id = fetch_fairy_quetion(fairy_id);

    -- 统计下
    CombatStatM.addFieldStat(query(fairy_id, "alias"), 1);

    -- -- 统计问题
    -- quetion_stat(quetion_id);

    return {
        ["fairy_id"]   = fairy_id,
        ["quetion_id"] = quetion_id,
    };
end

-- 这里只处理答案的结果（正确 or 错误）
function answer(pos, right)
    local grid = DungeonM.getGridByPos(pos);

    -- 如果不是仙女
    if GRID_TYPE_FAIRY ~= grid.type then
        trace("PinocchioM", "格子%d不是仙女", pos);
        return false;
    end

    -- 是否还有问题
    local quetion_id = grid.quetion_id or 0;
    if quetion_id <= 0 then
        trace("PinocchioM", "仙女已经没有问题了。");
        return false;
    end

    -- 撒谎标记，回答错误就是撒谎了
    ME.user.dbase:set("pinocchio_lie", 1 - right);

    -- 回答错误
    if 0 == right then
        -- 回答错误，鼻子变长 3 ~ 5
        local size = 3 + DungeonM.getRandSeed("nose_punish") % 3;

        ME.user:addAttrib("nose_size", size);

        -- 刷新一下装备属性
        PropM.refreshEffect(ME.user, "equip");

        grid.quetion_id = 0;

        local dbase = query(grid.fairy_id, "dbase") or {};
        -- TODO: 需要处理去留
        if dbase["sensitive"] or sizeof(PropM.fetchProps(ME.user, "villager_fighter")) <= 0 then
            grid:changeState(GRID_STATE_DISABLE);
        end

        -- 事件
        -- EventMgr.fire(event.ANSWER_FAIRY_QUETION, { ["pos"] = pos, ["right"] = right, ["fairy_id"] = grid.fairy_id  });

        return true;
    end

    -- 统计问题
    quetion_stat(quetion_id);

    local next_quetion = tonumber(query_quetion(quetion_id, "next_quetion"));

    -- 下一个问题
    grid.quetion_id = next_quetion;

    -- 需要点代价
    local require = query_quetion(quetion_id, "require");
    if sizeof(require) then
        for key, value in pairs(require) do
            if type(key) == "string" then
                ME.user:costAttrib(key, value);
            else
                -- 如果是装备，需要脱下来
                if EquipM.isEquipment(key) and
                    EquipM.isEquiped(key) then
                    local equipType = EquipM.query(key, "type");
                    EquipM.unequip(equipType, 1, true);
                end
            end

            -- 扣除数量
            ItemM.costAmount(ME.user, key, value);
        end
    end

    -- 如果鼻子较长
    if ME.user:queryAttrib("nose_size") > LIMIT_NOSE_SIZE then
        ME.user:costAttrib("nose_size", 1);

        -- 刷新一下装备属性
        PropM.refreshEffect(ME.user, "equip");

        -- 标记鼻子缩短了，用于提示
        ME.user.noseToShort = true;
    end

    local bonus = calc_quetion_bonus(quetion_id);

    if sizeof(bonus) > 0 and type(bonus[1]) ~= "table" then
        bonus = { bonus, };
    end

    for _, arr in ipairs(bonus) do
        BonusM.doBonus(arr);
    end

    -- 正确答题，增加经验
    local props = PropM.fetchProps(ME.user, "answer_add_exp");
    for _, prop in ipairs(props) do
        PropM.trigger(ME.user, prop[1], prop[2]);
    end

    if sizeof(PropM.fetchProps(ME.user, "villager_fighter")) <= 0 then
        grid:changeState(GRID_STATE_DISABLE);
    end

    -- TODO: 先记录下来
    if sizeof(bonus) > 0 then
        ME.user.pinocchioBonus = bonus;
    end

    -- -- 事件
    -- EventMgr.fire(event.ANSWER_FAIRY_QUETION, { ["pos"] = pos, ["right"] = right, ["fairy_id"] = grid.fairy_id });

    return true;
end

-- 尝试回答问题
function try_answer(pos, index)
    local grid = DungeonM.getGridByPos(pos);

    -- 不是仙女刚不奥格子
    if GRID_TYPE_FAIRY ~= grid.type then
        trace("PinocchioM", "不是仙女格子");
        return false;
    end

    -- 没有问题
    local quetion_id = tonumber(grid.quetion_id);
    if quetion_id <= 0 then
        trace("PinocchioM", "仙女没有问题了");
        return false;
    end

    -- 判断结果
    local rule = query_quetion(quetion_id, "rule");
    local mod = rules[rule];
    local right = mod.check_answer(quetion_id, index);

    trace("PinocchioM", "rule = %s, right = %d", rule, right);

    local ret = DungeonActionM.go("fairy_quetion", pos, right);

    return ret, right;
end

-- 开始对话
function get_say_hello(fairy_id, quetion_id)
    return query(fairy_id, "say_hello") .. query_quetion(quetion_id, "desc");
end

-- 招募仙女
function recruit(pos)
    local grid = DungeonM.getGridByPos(pos);

    -- 不是仙女刚不奥格子
    if GRID_TYPE_FAIRY ~= grid.type or GRID_STATE_DISABLE == grid.state or not grid.fairy_id then
        trace("PinocchioM", "不是仙女格子");
        return false;
    end

    -- 如果还有问题
    if grid.quetion_id and grid.quetion_id > 0 then
        trace("PinocchioM", "答完题再说");
        return false;
    end

    if sizeof(PropM.fetchProps(ME.user, "villager_fighter")) <= 0 then
        trace("PinocchioM", "有雅典娜才能招募");
        return false;
    end

    local dbase = query(grid.fairy_id, "dbase");
    local item_id = dbase["recruit"];
    if not item_id then
        trace("PinocchioM", "该仙女不能招募");
        return false;
    end

    grid:changeState(GRID_STATE_DISABLE);

    local bonus = { 1, item_id, 1, };

    BonusM.doBonus(bonus);

    -- 抛出通用建筑奖励事件
    EventMgr.fire(event.COMM_BUILDING_BONUS, {
        ["pos"]   = pos,
        ["type"]  = grid.type,
        ["bonus"] = {["bonus"] = bonus, },
        ["remainGrid"] = false,
    });

    return true;
end

-- 抛出奖励事件
function do_bonus_notify(para)
    if ME.user.pinocchioBonus then
        EventMgr.fire(event.COMM_BUILDING_BONUS, {
                ["pos"]   = para.pos,
                ["type"]  = para.type,
                ["bonus"] = {["bonus"] = ME.user.pinocchioBonus, },
                ["remainGrid"] = true,
            });

        ME.user.pinocchioBonus = nil;
    end
end
